package com.example.filter;

import com.example.security.CustomAuthenticationToken;
import com.example.service.CustomUserDetailsService;
import com.example.util.JwtUtil;
import io.jsonwebtoken.Claims;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class JwtTokenFilter extends OncePerRequestFilter {

    private static final Logger logger = LoggerFactory.getLogger(JwtTokenFilter.class);

    private final JwtUtil jwtUtil;
    private final StringRedisTemplate redisTemplate;
    private final CustomUserDetailsService userDetailsService;
    private final boolean jwtEnabled;  // 使用构造函数注入的 JWT 开关

    public JwtTokenFilter(JwtUtil jwtUtil, StringRedisTemplate redisTemplate, CustomUserDetailsService userDetailsService, boolean jwtEnabled) {
        this.jwtUtil = jwtUtil;
        this.redisTemplate = redisTemplate;
        this.userDetailsService = userDetailsService;
        this.jwtEnabled = jwtEnabled;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws java.io.IOException, javax.servlet.ServletException {

        String requestPath = request.getRequestURI();
        logger.debug("Processing request: {}", requestPath);
        String username;  // 从声明中获取未加密的用户名
        String uid;
        String tokenIdentifier;
        CustomAuthenticationToken authentication;

        if (jwtEnabled) {
            // 跳过 /auth/login 请求的 Token 验证
            if ("/auth/login".equals(requestPath)) {
                logger.info("Skipping token validation for login request");
                filterChain.doFilter(request, response);
                return;
            }

            // 检查 Token
            String token = request.getHeader("Authorization");
            if (token == null || !token.startsWith("Bearer ")) {
                logger.warn("Authorization header missing or malformed");
                response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid Token");
                return;
            }

            token = token.substring(7); // Remove "Bearer " prefix

            Claims claims = jwtUtil.validateToken(token);
            if (claims == null || jwtUtil.isTokenExpired(claims)) {
                logger.warn("Invalid or expired token");
                response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid Token");
                return;
            }

            tokenIdentifier = claims.getSubject();
            username = claims.get("username", String.class);
            uid = redisTemplate.opsForValue().get("auth:user:uid:" + tokenIdentifier);
            if (uid == null || StringUtils.isBlank(username)) {
                logger.warn("No UID or username found for token: {}, subject: {}", token, tokenIdentifier);
                response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid Token");
                return;
            }
            // 加载用户详细信息并创建认证对象
            authentication = userDetailsService.authenticateUser(username);
        } else {
            // JWT 验证已禁用，使用游客身份登录，并设置认证信息到 SecurityContextHolder
            username = "app_visitor";
            logger.debug("JWT 验证已禁用，使用游客身份登录，用户名: {}", username);
            uid = "30000006";
            UserDetails visitorUser = User.withUsername(username).password("").roles("VISITOR").build();
            authentication = new CustomAuthenticationToken(visitorUser, "", uid, visitorUser.getAuthorities());
        }

        // 将认证信息放入 SecurityContextHolder
        SecurityContextHolder.getContext().setAuthentication(authentication);

        // 将 UID 设置到请求属性中，以便后续使用
        request.setAttribute("req_uid", uid);
        logger.debug("UID {} retrieved and set in request", uid);

        filterChain.doFilter(request, response);
    }


    /**
     * 从 Redis 中获取 UID
     *
     * @param tokenIdentifier 加密后的用户名
     * @return UID 或 null 如果没有找到
     */
    private String getUidFromRedis(String tokenIdentifier) {
        // 从 Redis 中获取 UID
        return redisTemplate.opsForValue().get("auth:user:uid:" + tokenIdentifier);
    }

}
